﻿using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace OpenLightGroup.Common.Controls
{
    /// <summary>
    /// This class was taken from a forum post on Silverlight.net and enhanced with a few additional features.
    /// Here is the link to the forum post: http://forums.silverlight.net/forums/p/152761/372692.aspx
    /// </summary>
    [Obsolete("This control is no longer needed after enhancements to the ComboBox. This control will be removed in a future release and should be replaced as soon as possible.")]
    public class ComboBoxEx : ComboBox
    {

        private ObservableCollection<object> _internalItemList;
//        private IList _previouslySelectedItem;
        private Binding _selectedValueBinding;

        
        #region ctor
        public ComboBoxEx()
        {
            this.SelectionChanged += this.OnSelectionChanged;
            this.KeyUp += new System.Windows.Input.KeyEventHandler(ComboBoxEx_KeyUp);
            this.TextInput += new System.Windows.Input.TextCompositionEventHandler(ComboBoxEx_TextInput);

            this.IncludeNullItem = true;
            this.IsJumpToValueCaseSensitive = false;
        }



        //private static string GetKeyCharacter(System.Windows.Input.Key key)
        //{
        //    string keyValue = string.Empty;

        //    switch (key)
        //    {

        //        //Numbers
        //        case System.Windows.Input.Key.D0:
        //        case System.Windows.Input.Key.NumPad0:
        //            keyValue = "0";
        //            break;
        //        case System.Windows.Input.Key.D1:
        //        case System.Windows.Input.Key.NumPad1:
        //            keyValue = "1";
        //            break;
        //        case System.Windows.Input.Key.D2:
        //        case System.Windows.Input.Key.NumPad2:
        //            keyValue = "2";
        //            break;
        //        case System.Windows.Input.Key.D3:
        //        case System.Windows.Input.Key.NumPad3:
        //            keyValue = "3";
        //            break;
        //        case System.Windows.Input.Key.D4:
        //        case System.Windows.Input.Key.NumPad4:
        //            keyValue = "4";
        //            break;
        //        case System.Windows.Input.Key.D5:
        //        case System.Windows.Input.Key.NumPad5:
        //            keyValue = "5";
        //            break;
        //        case System.Windows.Input.Key.D6:
        //        case System.Windows.Input.Key.NumPad6:
        //            keyValue = "6";
        //            break;
        //        case System.Windows.Input.Key.D7:
        //        case System.Windows.Input.Key.NumPad7:
        //            keyValue = "7";
        //            break;
        //        case System.Windows.Input.Key.D8:
        //        case System.Windows.Input.Key.NumPad8:
        //            keyValue = "8";
        //            break;
        //        case System.Windows.Input.Key.D9:
        //        case System.Windows.Input.Key.NumPad9:
        //            keyValue = "9";
        //            break;

        //        //Special charaters
        //        case System.Windows.Input.Key.Add:
        //            keyValue = "+";
        //            break;
        //        case System.Windows.Input.Key.Decimal:
        //            keyValue = ".";
        //            break;
        //        case System.Windows.Input.Key.Divide:
        //            keyValue = "/";
        //            break;
        //        case System.Windows.Input.Key.Multiply:
        //            keyValue = "*";
        //            break;
        //        case System.Windows.Input.Key.Space:
        //            keyValue = " ";
        //            break;
        //        case System.Windows.Input.Key.Subtract:
        //            keyValue = "-";
        //            break;

        //        //None character keys
        //        case System.Windows.Input.Key.Alt:
        //        case System.Windows.Input.Key.Back:
        //        case System.Windows.Input.Key.CapsLock:
        //        case System.Windows.Input.Key.Ctrl:
        //        case System.Windows.Input.Key.Delete:
        //        case System.Windows.Input.Key.Down:
        //        case System.Windows.Input.Key.End:
        //        case System.Windows.Input.Key.Enter:
        //        case System.Windows.Input.Key.Escape:
        //        case System.Windows.Input.Key.F1:
        //        case System.Windows.Input.Key.F10:
        //        case System.Windows.Input.Key.F11:
        //        case System.Windows.Input.Key.F12:
        //        case System.Windows.Input.Key.F2:
        //        case System.Windows.Input.Key.F3:
        //        case System.Windows.Input.Key.F4:
        //        case System.Windows.Input.Key.F5:
        //        case System.Windows.Input.Key.F6:
        //        case System.Windows.Input.Key.F7:
        //        case System.Windows.Input.Key.F8:
        //        case System.Windows.Input.Key.F9:
        //        case System.Windows.Input.Key.Home:
        //        case System.Windows.Input.Key.Insert:
        //        case System.Windows.Input.Key.Left:
        //        case System.Windows.Input.Key.None:
        //        case System.Windows.Input.Key.PageDown:
        //        case System.Windows.Input.Key.PageUp:
        //        case System.Windows.Input.Key.Right:
        //        case System.Windows.Input.Key.Shift:
        //        case System.Windows.Input.Key.Tab:
        //        case System.Windows.Input.Key.Unknown:
        //        case System.Windows.Input.Key.Up:
        //            break;

        //        //Letters
        //        default:
        //            keyValue = key.ToString();
        //            break;
        //    }


        //    return keyValue;
        //}


        #endregion

        #region Properties

        public bool IncludeNullItem { get; set; }
        public string JumpToPropertyName { get; set; }
        public bool IsJumpToValueCaseSensitive { get; set; }


        #region NullValueContent

        #region NullValueContentProperty
        /// <summary>
        /// Identifies the NullValueContent dependency property.
        /// </summary>
        public static DependencyProperty NullValueContentProperty = DependencyProperty.Register("NullValueContent", typeof(object), typeof(ComboBoxEx), new PropertyMetadata(new PropertyChangedCallback(ComboBoxEx.OnNullValueContentPropertyChanged)));
        #endregion

        #region NullValueContent
        /// <summary>
        /// Gets or sets the NullValueContent value.
        /// </summary>
        public object NullValueContent
        {
            get { return (object)base.GetValue(ComboBoxEx.NullValueContentProperty); }
            set { base.SetValue(ComboBoxEx.NullValueContentProperty, value); }
        }
        #endregion

        #region OnNullValueContentPropertyChanged
        private static void OnNullValueContentPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ComboBoxEx)d).OnNullValueContentChanged((object)e.NewValue);
        }
        #endregion

        #endregion

        #region NullValueContentTemplate

        #region NullValueContentTemplateProperty
        /// <summary>
        /// Identifies the NullValueContentTemplate dependency property.
        /// </summary>
        public static DependencyProperty NullValueContentTemplateProperty = DependencyProperty.Register("NullValueContentTemplate", typeof(DataTemplate), typeof(ComboBoxEx), new PropertyMetadata(new PropertyChangedCallback(ComboBoxEx.OnNullValueContentTemplatePropertyChanged)));
        #endregion

        #region NullValueContentTemplate
        /// <summary>
        /// Gets or sets the NullValueContentTemplate value.
        /// </summary>
        public DataTemplate NullValueContentTemplate
        {
            get { return (DataTemplate)base.GetValue(ComboBoxEx.NullValueContentTemplateProperty); }
            set { base.SetValue(ComboBoxEx.NullValueContentTemplateProperty, value); }
        }
        #endregion

        #region OnNullValueContentTemplatePropertyChanged
        private static void OnNullValueContentTemplatePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ComboBoxEx)d).OnNullValueContentTemplateChanged((DataTemplate)e.NewValue);
        }
        #endregion


        #endregion

        #region NullValueListBoxItem

        protected ListBoxItem NullValueListBoxItem { get; set; }

        #endregion

        #endregion

        #region Methods

        //ITL added
        void ComboBoxEx_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (e.Key == System.Windows.Input.Key.Delete || e.Key == System.Windows.Input.Key.Back)
            {
                this.SelectedValue = null;
                e.Handled = true;
            }
        }

        void ComboBoxEx_TextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
        {
            //ToDo collect keystrokes and combine them to allow for multiple letters
            if (!string.IsNullOrEmpty(this.JumpToPropertyName))
            {
                string keyValue = e.Text;

                if (!string.IsNullOrEmpty(keyValue))
                {

                    var items = from object i in this.Items
                                where i != null && CompareJumpToValue(i.GetType()
                                    .GetProperty(this.JumpToPropertyName)
                                    .GetValue(i, null).ToString(), keyValue)
                                select i;

                    object firstItem = items.FirstOrDefault();

                    if (firstItem != null)
                    {
                        this.SelectedItem = firstItem;
                    }


                }

                e.Handled = true;
            }
        }

        protected bool CompareJumpToValue(string itemValue, string textInput)
        {

            bool result = false;

            if (this.IsJumpToValueCaseSensitive)
            {
                result = itemValue.StartsWith(textInput, StringComparison.InvariantCulture);
            }
            else
            {
                result = itemValue.StartsWith(textInput, StringComparison.OrdinalIgnoreCase);
            }


            return result;
        }

        /// <summary>
        /// Overriden to allow an event handler to be attached to the TextInput event of the item container.
        /// </summary>
        /// <returns></returns>
        protected override DependencyObject GetContainerForItemOverride()
        {
            var container = base.GetContainerForItemOverride();

            var uiContainer = container as UIElement;

            if (uiContainer != null)
            {

                uiContainer.KeyUp += new System.Windows.Input.KeyEventHandler(ComboBoxEx_KeyUp);
                uiContainer.TextInput += new System.Windows.Input.TextCompositionEventHandler(ComboBoxEx_TextInput);

            }

            return container;


        }

        #region OnItemsChanged
        protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Reset:
                    this.NullValueListBoxItem = null;
                    break;
                case NotifyCollectionChangedAction.Remove:
                case NotifyCollectionChangedAction.Replace:
                    if (e.OldItems.Contains(null)) this.NullValueListBoxItem = null;
                    break;
            }

            object obj = this.SelectedItem;
            base.OnItemsChanged(e);


            //ITL changed
            IList items = this.ItemsSource as IList;

            INotifyCollectionChanged o = this.ItemsSource as INotifyCollectionChanged;

            if (o != null && o != this._internalItemList)
            {
                o.CollectionChanged += new NotifyCollectionChangedEventHandler(o_CollectionChanged);
            }


            var binding = GetBindingExpression(SelectedValueProperty);

            if (binding != null)
            {
                  this._selectedValueBinding = binding.ParentBinding;
            }
          

            //var itemBinding = GetBindingExpression(SelectedItemProperty);


            if (this.IncludeNullItem && items != null && !items.Contains(null))
            {
                //try
                //{
                //    items.Insert(0, null);

                //}
                //catch (Exception ex)
                //{

                //    var x = ex;
                //}


                //var binding = this.GetBindingExpression(ComboBoxEx.ItemsSourceProperty);

                //binding.ParentBinding.Path = new PropertyPath(string.Empty);

                //binding.ParentBinding.Source = items;

                //SetBinding(ComboBoxEx.ItemsSourceProperty, binding.ParentBinding);

                _internalItemList = new ObservableCollection<object>();

                //items2.AddRange(items.Cast<object>());

                items.Cast<object>().ToList().ForEach(item => _internalItemList.Add(item));


                _internalItemList.Insert(0, null);

                this.ItemsSource = _internalItemList;

                //if (this._selectValueBinding != null)
                //{
                //       SetBinding(SelectedValueProperty, binding.ParentBinding);

                //}
             
                this._internalItemList.CollectionChanged -= new NotifyCollectionChangedEventHandler(o_CollectionChanged);

                //items2.CollectionChanged += new NotifyCollectionChangedEventHandler(o_CollectionChanged);

            }

            this.SelectedItem = obj;

            if (obj == null)
            {
                this.SelectedIndex = 0;
            }

        }

        void o_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {

            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    IList items = this.ItemsSource as IList;

                    e.NewItems.Cast<object>().ToList().ForEach(i => items.Add(i));


                    if (!items.Contains(null))
                    {
                        items.Insert(0, null);
                    }

                    break;

                case NotifyCollectionChangedAction.Remove:
                    break;
                case NotifyCollectionChangedAction.Replace:
                    break;
                case NotifyCollectionChangedAction.Reset:
                    break;
                default:
                    break;
            }


            //IList items = this.ItemsSource as IList;


            //if (this.IncludeNullItem && items != null && !items.Contains(null))
            //{

            //    List<object> items2 = new List<object>();

            //    items2.AddRange(items.Cast<object>());

            //    items2.Insert(0, null);

            //    //this.ItemsSource = items2;

            //}
        }



        #endregion

        #region OnNullValueContentChanged
        private void OnNullValueContentChanged(object newValue)
        {
            if (this.NullValueListBoxItem != null)
            {
                this.NullValueListBoxItem.Content = newValue;
                this.OnApplyTemplate();
            }
        }
        #endregion

        #region OnNullValueContentTemplateChanged
        private void OnNullValueContentTemplateChanged(DataTemplate newValue)
        {
            if (this.NullValueListBoxItem != null)
            {
                this.NullValueListBoxItem.ContentTemplate = newValue;
                this.OnApplyTemplate();
            }
        }
        #endregion

        #region OnSelectionChanged
        protected virtual void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            // ITL - change
            var binding = GetBindingExpression(SelectedValueProperty);
              
            if (this._selectedValueBinding != null && binding == null)
            {
                SetBinding(SelectedValueProperty, this._selectedValueBinding);
            }

            //if (_previouslySelectedItem == null)
            //{
            //    _previouslySelectedItem = e.AddedItems;
            //}

            //if (this._previouslySelectedItem != e.AddedItems)
            //{

            //    var itemBinding = GetBindingExpression(SelectedItemProperty);

            if (this.SelectedItem == this.NullValueListBoxItem || this.SelectedItem == null || this.SelectedIndex == -1)
            {

                if (this.NullValueListBoxItem != null)
                    this.NullValueListBoxItem.IsSelected = true;

            }
            //    else

            //        if (this.NullValueListBoxItem != null)
            //            this.NullValueListBoxItem.IsSelected = false;
            //}
        }
        #endregion

        #region PrepareContainerForItemOverride
        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {
            base.PrepareContainerForItemOverride(element, item);

            ListBoxItem item2 = element as ListBoxItem;
            if (item == null && item2 != null)
            {
                item2.Content = this.NullValueContent;
                item2.ContentTemplate = this.NullValueContentTemplate;
                this.NullValueListBoxItem = item2;
            }
        }
        #endregion


        #endregion
    }
}
